#include "ymodem.h"
#include "delay.h"
#include "flash.h"

YModem ymodem = {WAIT_ENTER_SYSTEM, 0, 0, ApplicationAddress, 0, {0}};

Buffer recvBuf;

void YModem_ACK(void) {
	printf("%c\r", YMODEM_ACK);
  
    
}

void YModem_NACK(void) {
	printf("%c\r", YMODEM_NAK);

 
}

void YModem_C(void) {
	printf("%c\r", YMODEM_C);
   
 
}

void Set_YModem_Status(ProcessStatus process) {
	ymodem.process = process;
}

ProcessStatus Get_YModem_Status(void) {
	ProcessStatus process = ymodem.process;
	return process;
}

void YModem_Start(YModem_Callback cb) {
	if (ymodem.status == 0) {
		ymodem.cb = cb;
	}
}

void YModem_Recv(Buffer *p) {
	uint8_t type = p->data[0];
	switch (ymodem.status) {
		case 0:
			if (type == YMODEM_SOH) {
				ymodem.process = BUSY;
				ymodem.addr = ApplicationAddress;
				FlashErase(ymodem.addr, ERASE_SECTORS);
				YModem_ACK();
				YModem_C();
				ymodem.status++;
			}
			else if (type == '1') {
				ymodem.process = START_PROGRAM;
			}
			else if (type == '2') {
				ymodem.process = UPDATE_PROGRAM;
			}
			else if (type == '3') {
				ymodem.process = SET_PARAMETER;
			}
			break;
		case 1:
			if (type == YMODEM_SOH || type == YMODEM_STX) {
				if (type == YMODEM_SOH) {
					FlashWrite(ymodem.addr, &p->data[3], 128);
					ymodem.addr += 128;
				}
				else {
					FlashWrite(ymodem.addr, &p->data[3], 1024);
					ymodem.addr += 1024;
				}
				YModem_ACK();
			}
			else if (type == YMODEM_EOT) {
				YModem_NACK();
				ymodem.status++;
			}
			else {
				ymodem.status = 0;
			}
			break;
		case 2:
			if (type == YMODEM_EOT) {
				YModem_ACK();
				YModem_C();
				ymodem.status++;
			}
			break;
		case 3:
			if (type == YMODEM_SOH) {
				YModem_ACK();
				ymodem.status = 0;
				ymodem.process = UPDATE_SUCCESS;
			}
	}
	p->len = 0;
}

void USART1_IRQHandler(void) {
	uint8_t c;
	if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
		c = (uint8_t)USART_ReceiveData(USART1); 
		recvBuf.data[recvBuf.len++] = c;
		TIM3->CNT = 0;
		TIM_Cmd(TIM3, ENABLE);	
	}
}

void TIM3_IRQHandler(void) {
	if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
		TIM_Cmd(TIM3, DISABLE);	
		YModem_Recv(&recvBuf);
	}
}
